1   /*
2    * Copyright (C) 2014 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.base;
18  
19  import static com.google.common.base.Preconditions.checkNotNull;
20  
21  import com.google.common.annotations.GwtCompatible;
22  
23  import javax.annotation.Nullable;
24  
25  /**
26   * Helper functions that operate on any {@code Object}, and are not already provided in
27   * {@link java.util.Objects}.
28   *
29   * <p>See the Guava User Guide on <a
30   * href="http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained">writing
31   * {@code Object} methods with {@code MoreObjects}</a>.
32   *
33   * @author Laurence Gonsalves
34   * @since 18.0 (since 2.0 as {@code Objects})
35   */
36  @GwtCompatible
37  public final class MoreObjects {
38    /**
39     * Returns the first of two given parameters that is not {@code null}, if either is, or otherwise
40     * throws a {@link NullPointerException}.
41     *
42     * <p><b>Note:</b> if {@code first} is represented as an {@link Optional}, this can be
43     * accomplished with {@link Optional#or(Object) first.or(second)}. That approach also allows for
44     * lazy evaluation of the fallback instance, using {@link Optional#or(Supplier)
45     * first.or(supplier)}.
46     *
47     * @return {@code first} if it is non-null; otherwise {@code second} if it is non-null
48     * @throws NullPointerException if both {@code first} and {@code second} are null
49     * @since 18.0 (since 3.0 as {@code Objects.firstNonNull()}.
50     */
51    public static <T> T firstNonNull(@Nullable T first, @Nullable T second) {
52      return first != null ? first : checkNotNull(second);
53    }
54  
55    /**
56     * Creates an instance of {@link ToStringHelper}.
57     *
58     * <p>This is helpful for implementing {@link Object#toString()}.
59     * Specification by example: <pre>   {@code
60     *   // Returns "ClassName{}"
61     *   MoreObjects.toStringHelper(this)
62     *       .toString();
63     *
64     *   // Returns "ClassName{x=1}"
65     *   MoreObjects.toStringHelper(this)
66     *       .add("x", 1)
67     *       .toString();
68     *
69     *   // Returns "MyObject{x=1}"
70     *   MoreObjects.toStringHelper("MyObject")
71     *       .add("x", 1)
72     *       .toString();
73     *
74     *   // Returns "ClassName{x=1, y=foo}"
75     *   MoreObjects.toStringHelper(this)
76     *       .add("x", 1)
77     *       .add("y", "foo")
78     *       .toString();
79     *
80     *   // Returns "ClassName{x=1}"
81     *   MoreObjects.toStringHelper(this)
82     *       .omitNullValues()
83     *       .add("x", 1)
84     *       .add("y", null)
85     *       .toString();
86     *   }}</pre>
87     *
88     * <p>Note that in GWT, class names are often obfuscated.
89     *
90     * @param self the object to generate the string for (typically {@code this}), used only for its
91     *     class name
92     * @since 18.0 (since 2.0 as {@code Objects.toStringHelper()}.
93     */
94    public static ToStringHelper toStringHelper(Object self) {
95      return new ToStringHelper(simpleName(self.getClass()));
96    }
97  
98    /**
99     * Creates an instance of {@link ToStringHelper} in the same manner as {@link
100    * #toStringHelper(Object)}, but using the simple name of {@code clazz} instead of using an
101    * instance's {@link Object#getClass()}.
102    *
103    * <p>Note that in GWT, class names are often obfuscated.
104    *
105    * @param clazz the {@link Class} of the instance
106    * @since 18.0 (since 7.0 as {@code Objects.toStringHelper()}.
107    */
108   public static ToStringHelper toStringHelper(Class<?> clazz) {
109     return new ToStringHelper(simpleName(clazz));
110   }
111 
112   /**
113    * Creates an instance of {@link ToStringHelper} in the same manner as {@link
114    * #toStringHelper(Object)}, but using {@code className} instead of using an instance's {@link
115    * Object#getClass()}.
116    *
117    * @param className the name of the instance type
118    * @since 18.0 (since 7.0 as {@code Objects.toStringHelper()}.
119    */
120   public static ToStringHelper toStringHelper(String className) {
121     return new ToStringHelper(className);
122   }
123 
124   /**
125    * {@link Class#getSimpleName()} is not GWT compatible yet, so we
126    * provide our own implementation.
127    */
128   // Package-private so Objects can call it.
129   static String simpleName(Class<?> clazz) {
130     String name = clazz.getName();
131 
132     // the nth anonymous class has a class name ending in "Outer$n"
133     // and local inner classes have names ending in "Outer.$1Inner"
134     name = name.replaceAll("\\$[0-9]+", "\\$");
135 
136     // we want the name of the inner class all by its lonesome
137     int start = name.lastIndexOf('$');
138 
139     // if this isn't an inner class, just find the start of the
140     // top level class name.
141     if (start == -1) {
142       start = name.lastIndexOf('.');
143     }
144     return name.substring(start + 1);
145   }
146 
147   /**
148    * Support class for {@link MoreObjects#toStringHelper}.
149    *
150    * @author Jason Lee
151    * @since 18.0 (since 2.0 as {@code Objects.ToStringHelper}.
152    */
153   public static final class ToStringHelper {
154     private final String className;
155     private ValueHolder holderHead = new ValueHolder();
156     private ValueHolder holderTail = holderHead;
157     private boolean omitNullValues = false;
158 
159     /**
160      * Use {@link MoreObjects#toStringHelper(Object)} to create an instance.
161      */
162     private ToStringHelper(String className) {
163       this.className = checkNotNull(className);
164     }
165 
166     /**
167      * Configures the {@link ToStringHelper} so {@link #toString()} will ignore
168      * properties with null value. The order of calling this method, relative
169      * to the {@code add()}/{@code addValue()} methods, is not significant.
170      *
171      * @since 18.0 (since 12.0 as {@code Objects.ToStringHelper.omitNullValues()}.
172      */
173     public ToStringHelper omitNullValues() {
174       omitNullValues = true;
175       return this;
176     }
177 
178     /**
179      * Adds a name/value pair to the formatted output in {@code name=value}
180      * format. If {@code value} is {@code null}, the string {@code "null"}
181      * is used, unless {@link #omitNullValues()} is called, in which case this
182      * name/value pair will not be added.
183      */
184     public ToStringHelper add(String name, @Nullable Object value) {
185       return addHolder(name, value);
186     }
187 
188     /**
189      * Adds a name/value pair to the formatted output in {@code name=value}
190      * format.
191      *
192      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
193      */
194     public ToStringHelper add(String name, boolean value) {
195       return addHolder(name, String.valueOf(value));
196     }
197 
198     /**
199      * Adds a name/value pair to the formatted output in {@code name=value}
200      * format.
201      *
202      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
203      */
204     public ToStringHelper add(String name, char value) {
205       return addHolder(name, String.valueOf(value));
206     }
207 
208     /**
209      * Adds a name/value pair to the formatted output in {@code name=value}
210      * format.
211      *
212      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
213      */
214     public ToStringHelper add(String name, double value) {
215       return addHolder(name, String.valueOf(value));
216     }
217 
218     /**
219      * Adds a name/value pair to the formatted output in {@code name=value}
220      * format.
221      *
222      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
223      */
224     public ToStringHelper add(String name, float value) {
225       return addHolder(name, String.valueOf(value));
226     }
227 
228     /**
229      * Adds a name/value pair to the formatted output in {@code name=value}
230      * format.
231      *
232      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
233      */
234     public ToStringHelper add(String name, int value) {
235       return addHolder(name, String.valueOf(value));
236     }
237 
238     /**
239      * Adds a name/value pair to the formatted output in {@code name=value}
240      * format.
241      *
242      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
243      */
244     public ToStringHelper add(String name, long value) {
245       return addHolder(name, String.valueOf(value));
246     }
247 
248     /**
249      * Adds an unnamed value to the formatted output.
250      *
251      * <p>It is strongly encouraged to use {@link #add(String, Object)} instead
252      * and give value a readable name.
253      *
254      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
255      */
256     public ToStringHelper addValue(@Nullable Object value) {
257       return addHolder(value);
258     }
259 
260     /**
261      * Adds an unnamed value to the formatted output.
262      *
263      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
264      *
265      * <p>It is strongly encouraged to use {@link #add(String, boolean)} instead
266      * and give value a readable name.
267      *
268      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
269      */
270     public ToStringHelper addValue(boolean value) {
271       return addHolder(String.valueOf(value));
272     }
273 
274     /**
275      * Adds an unnamed value to the formatted output.
276      *
277      * <p>It is strongly encouraged to use {@link #add(String, char)} instead
278      * and give value a readable name.
279      *
280      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
281      */
282     public ToStringHelper addValue(char value) {
283       return addHolder(String.valueOf(value));
284     }
285 
286     /**
287      * Adds an unnamed value to the formatted output.
288      *
289      * <p>It is strongly encouraged to use {@link #add(String, double)} instead
290      * and give value a readable name.
291      *
292      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
293      */
294     public ToStringHelper addValue(double value) {
295       return addHolder(String.valueOf(value));
296     }
297 
298     /**
299      * Adds an unnamed value to the formatted output.
300      *
301      * <p>It is strongly encouraged to use {@link #add(String, float)} instead
302      * and give value a readable name.
303      *
304      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
305      */
306     public ToStringHelper addValue(float value) {
307       return addHolder(String.valueOf(value));
308     }
309 
310     /**
311      * Adds an unnamed value to the formatted output.
312      *
313      * <p>It is strongly encouraged to use {@link #add(String, int)} instead
314      * and give value a readable name.
315      *
316      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
317      */
318     public ToStringHelper addValue(int value) {
319       return addHolder(String.valueOf(value));
320     }
321 
322     /**
323      * Adds an unnamed value to the formatted output.
324      *
325      * <p>It is strongly encouraged to use {@link #add(String, long)} instead
326      * and give value a readable name.
327      *
328      * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}.
329      */
330     public ToStringHelper addValue(long value) {
331       return addHolder(String.valueOf(value));
332     }
333 
334     /**
335      * Returns a string in the format specified by
336      * {@link MoreObjects#toStringHelper(Object)}.
337      *
338      * <p>After calling this method, you can keep adding more properties to later
339      * call toString() again and get a more complete representation of the
340      * same object; but properties cannot be removed, so this only allows
341      * limited reuse of the helper instance. The helper allows duplication of
342      * properties (multiple name/value pairs with the same name can be added).
343      */
344     @Override public String toString() {
345       // create a copy to keep it consistent in case value changes
346       boolean omitNullValuesSnapshot = omitNullValues;
347       String nextSeparator = "";
348       StringBuilder builder = new StringBuilder(32).append(className)
349           .append('{');
350       for (ValueHolder valueHolder = holderHead.next; valueHolder != null;
351           valueHolder = valueHolder.next) {
352         if (!omitNullValuesSnapshot || valueHolder.value != null) {
353           builder.append(nextSeparator);
354           nextSeparator = ", ";
355 
356           if (valueHolder.name != null) {
357             builder.append(valueHolder.name).append('=');
358           }
359           builder.append(valueHolder.value);
360         }
361       }
362       return builder.append('}').toString();
363     }
364 
365     private ValueHolder addHolder() {
366       ValueHolder valueHolder = new ValueHolder();
367       holderTail = holderTail.next = valueHolder;
368       return valueHolder;
369     }
370 
371     private ToStringHelper addHolder(@Nullable Object value) {
372       ValueHolder valueHolder = addHolder();
373       valueHolder.value = value;
374       return this;
375     }
376 
377     private ToStringHelper addHolder(String name, @Nullable Object value) {
378       ValueHolder valueHolder = addHolder();
379       valueHolder.value = value;
380       valueHolder.name = checkNotNull(name);
381       return this;
382     }
383 
384     private static final class ValueHolder {
385       String name;
386       Object value;
387       ValueHolder next;
388     }
389   }
390 
391   private MoreObjects() {}
392 }